package com.kaowen.spider;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.swing.DropMode;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.google.gson.Gson;

public class SpiderForGk66ScoreUI implements ActionListener {

	private JFrame frmurl;
	private JTextField lowScoreTextField;
	private JTextField highScoreTextField;
	private JTextField codeTextField;
	private JTextField cookieTextField;
	private JTextField viewStateTextField;
	private JTextField eventValidationTextField;
	private JTextField yearTextField;
	private JTextField savePathTextField;
	private JPanel codePanel;
	private JTextArea resultTextArea;


	private JButton beginButton;
	private JButton stopButton;
	private JButton browserButton;

	private JLabel statusLabel;

	private String cookie = null;
	private String __VIEWSTATE = null;
	private String __EVENTVALIDATION = null;

	private Map<String, String> nf = null;
	private Map<String, String> wl = null;
	private Map<String, String> bz = null;
	private JCheckBox bCheckBox;
	private JCheckBox zCheckBox;
	private JCheckBox wCheckBox;
	private JCheckBox lCheckBox;

	private int lowScore;
	private int highScore;

	private String savePath;

	private String code = null;
	
	private SwingWorker<String, String> worker;

	private Gson gson = new Gson();
	private HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); // 创建HttpClientBuilder
	
	private boolean stopFlag = false;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					SpiderForGk66ScoreUI window = new SpiderForGk66ScoreUI();
					window.frmurl.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public SpiderForGk66ScoreUI() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frmurl = new JFrame();
		frmurl.setTitle("高招网按分数查询URL抓取工具");
		frmurl.setBounds(100, 100, 780, 600);
		frmurl.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frmurl.getContentPane().setLayout(null);

		statusLabel = new JLabel("");
		statusLabel.setBounds(10, 536, 764, 15);
		frmurl.getContentPane().add(statusLabel);

		JSeparator separator = new JSeparator();
		separator.setBounds(0, 529, 784, 32);
		frmurl.getContentPane().add(separator);

		beginButton = new JButton("开始");
		beginButton.addActionListener(this);
		beginButton.setBounds(573, 177, 75, 23);
		frmurl.getContentPane().add(beginButton);

		JLabel lblCookies = new JLabel("Cookies：");
		lblCookies.setHorizontalAlignment(SwingConstants.RIGHT);
		lblCookies.setBounds(21, 57, 106, 15);
		frmurl.getContentPane().add(lblCookies);

		JLabel label_1 = new JLabel("分数：");
		label_1.setHorizontalAlignment(SwingConstants.RIGHT);
		label_1.setBounds(73, 25, 54, 15);
		frmurl.getContentPane().add(label_1);

		lowScoreTextField = new JTextField();
		lowScoreTextField.setHorizontalAlignment(SwingConstants.CENTER);
		lowScoreTextField.setToolTipText("最小分数");
		lowScoreTextField.setText("0");
		lowScoreTextField.setBounds(137, 22, 35, 21);
		frmurl.getContentPane().add(lowScoreTextField);
		lowScoreTextField.setColumns(10);

		JLabel label_2 = new JLabel("到");
		label_2.setHorizontalAlignment(SwingConstants.CENTER);
		label_2.setBounds(174, 25, 24, 15);
		frmurl.getContentPane().add(label_2);

		highScoreTextField = new JTextField();
		highScoreTextField.setHorizontalAlignment(SwingConstants.CENTER);
		highScoreTextField.setToolTipText("最大分数");
		highScoreTextField.setText("750");
		highScoreTextField.setColumns(10);
		highScoreTextField.setBounds(201, 22, 36, 21);
		frmurl.getContentPane().add(highScoreTextField);

		JLabel lblViewstate = new JLabel("View State：");
		lblViewstate.setHorizontalAlignment(SwingConstants.RIGHT);
		lblViewstate.setBounds(10, 88, 117, 15);
		frmurl.getContentPane().add(lblViewstate);

		JLabel lblEventvalidation = new JLabel("Event Validation：");
		lblEventvalidation.setHorizontalAlignment(SwingConstants.RIGHT);
		lblEventvalidation.setBounds(10, 119, 117, 15);
		frmurl.getContentPane().add(lblEventvalidation);

		JLabel label_3 = new JLabel("验证码：");
		label_3.setHorizontalAlignment(SwingConstants.RIGHT);
		label_3.setBounds(73, 181, 54, 15);
		frmurl.getContentPane().add(label_3);

		codeTextField = new JTextField();
		codeTextField.setBounds(137, 178, 36, 21);
		frmurl.getContentPane().add(codeTextField);
		codeTextField.setColumns(10);

		codePanel = new JPanel();
		codePanel.setBounds(183, 177, 54, 42);
		frmurl.getContentPane().add(codePanel);

		cookieTextField = new JTextField();
		cookieTextField.setBounds(137, 54, 596, 21);
		frmurl.getContentPane().add(cookieTextField);
		cookieTextField.setColumns(10);

		viewStateTextField = new JTextField();
		viewStateTextField.setColumns(10);
		viewStateTextField.setBounds(137, 85, 596, 21);
		frmurl.getContentPane().add(viewStateTextField);

		eventValidationTextField = new JTextField();
		eventValidationTextField.setColumns(10);
		eventValidationTextField.setBounds(137, 116, 596, 21);
		frmurl.getContentPane().add(eventValidationTextField);

		JLabel label_4 = new JLabel("年份：");
		label_4.setHorizontalAlignment(SwingConstants.RIGHT);
		label_4.setBounds(563, 25, 54, 15);
		frmurl.getContentPane().add(label_4);

		yearTextField = new JTextField();
		yearTextField.setToolTipText("多个年份用英文逗号“,”分隔");
		yearTextField.setText("2014");
		yearTextField.setBounds(627, 22, 106, 21);
		frmurl.getContentPane().add(yearTextField);
		yearTextField.setColumns(10);

		JLabel label_5 = new JLabel("保存路径：");
		label_5.setHorizontalAlignment(SwingConstants.RIGHT);
		label_5.setBounds(10, 150, 117, 15);
		frmurl.getContentPane().add(label_5);

		savePathTextField = new JTextField();
		savePathTextField.setText("C:\\");
		savePathTextField.setColumns(10);
		savePathTextField.setBounds(137, 147, 541, 21);
		frmurl.getContentPane().add(savePathTextField);

		browserButton = new JButton("...");
		browserButton.addActionListener(this);
		browserButton.setBounds(688, 147, 45, 23);
		frmurl.getContentPane().add(browserButton);
		
		stopButton = new JButton("停止");
		stopButton.addActionListener(this);
		stopButton.setBounds(658, 177, 75, 23);
		frmurl.getContentPane().add(stopButton);
		
		resultTextArea = new JTextArea();
		resultTextArea.setEditable(false);
		resultTextArea.setLineWrap(true);
		resultTextArea.setDropMode(DropMode.INSERT);
		resultTextArea.setBounds(21, 230, 712, 289);
		frmurl.getContentPane().add(resultTextArea);
		
		label = new JLabel("本专：");
		label.setHorizontalAlignment(SwingConstants.RIGHT);
		label.setBounds(256, 25, 45, 15);
		frmurl.getContentPane().add(label);
		
		label_6 = new JLabel("文理：");
		label_6.setHorizontalAlignment(SwingConstants.RIGHT);
		label_6.setBounds(405, 25, 54, 15);
		frmurl.getContentPane().add(label_6);
		
		bCheckBox = new JCheckBox("本");
		bCheckBox.setSelected(true);
		bCheckBox.setBounds(307, 21, 45, 23);
		frmurl.getContentPane().add(bCheckBox);
		
		zCheckBox = new JCheckBox("专");
		zCheckBox.setSelected(true);
		zCheckBox.setBounds(354, 21, 45, 23);
		frmurl.getContentPane().add(zCheckBox);
		
		wCheckBox = new JCheckBox("文");
		wCheckBox.setSelected(true);
		wCheckBox.setBounds(465, 21, 45, 23);
		frmurl.getContentPane().add(wCheckBox);
		
		lCheckBox = new JCheckBox("理");
		lCheckBox.setSelected(true);
		lCheckBox.setBounds(512, 21, 45, 23);
		frmurl.getContentPane().add(lCheckBox);
		
		refreshButton = new JButton("刷新");
		refreshButton.addActionListener(this);
		refreshButton.setBounds(247, 177, 65, 23);
		frmurl.getContentPane().add(refreshButton);
	}

	@Override
	public void actionPerformed(ActionEvent event) {
		// TODO Auto-generated method stub
		if (event.getSource().equals(browserButton)) {
			JFileChooser chooser = new JFileChooser();
			chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
			int state = chooser.showOpenDialog(frmurl);
			if (JFileChooser.APPROVE_OPTION == state) {
				File f = chooser.getSelectedFile();
				savePathTextField.setText(f.getAbsolutePath());
			}
		} else if (event.getSource().equals(beginButton)) {
			this.statusLabel.setText(execute());
		} else if (event.getSource().equals(stopButton)) {
			stopFlag = true;
		} else if(event.getSource().equals(refreshButton)) {
			if(cookieTextField.getText()!=null && !"".equals(cookieTextField.getText())){
				ImageIcon icon = new ImageIcon(codewj());
				codePanel.getGraphics().drawImage(icon.getImage(), 0, 0, null);
			}
			statusLabel.setText("请首先填写Cookies信息");
		}
	}

	private String execute() {
		String rtv = "";
		try {
			cookie = this.cookieTextField.getText();
			if (cookie == null || "".equals(cookie)) {
				return "请填写Cookie";
			}
			__VIEWSTATE = this.viewStateTextField.getText();
			if (__VIEWSTATE == null || "".equals(__VIEWSTATE)) {
				return "请填写View State";
			}
			__EVENTVALIDATION = this.eventValidationTextField.getText();
			if (__EVENTVALIDATION == null || "".equals(__EVENTVALIDATION)) {
				return "请填写Event Validation";
			}
			nf = new TreeMap<String, String>();
			String yearString = this.yearTextField.getText();
			if (yearString == null || "".equals(yearString)) {
				return "请填写年份";
			}
			for (String year : yearString.split(",")) {
				nf.put(String.valueOf(year).substring(2, 4), year + "年");
			}
			wl = new HashMap<String,String>();
			if(wCheckBox.isSelected()){
				wl.put("w","文科");
			}
			if(lCheckBox.isSelected()){
				wl.put("l","理科");
			}
			bz = new HashMap<String,String>();
			if(bCheckBox.isSelected()){
				bz.put("b","本科");
			}
			if(zCheckBox.isSelected()){
				bz.put("z","专科");
			}
			String highScoreStr = this.highScoreTextField.getText();
			if (highScoreStr == null || "".equals(highScoreStr)) {
				return "请填写最高分数";
			}
			this.highScore = Integer.parseInt(highScoreStr);
			String lowScoreStr = this.lowScoreTextField.getText();
			if (lowScoreStr == null || "".equals(lowScoreStr)) {
				return "请填写最低分数";
			}
			this.lowScore = Integer.parseInt(lowScoreStr);
			this.savePath = this.savePathTextField.getText();
			if (savePath == null || "".equals(savePath)) {
				return "请填写保存路径";
			}
			File file = new File(this.savePath);
			if (!file.exists()) {
				if (!file.createNewFile()) {
					return "无法创建目录：" + savePath;
				}
			}

			code = this.codeTextField.getText();
			if (code == null || "".equals(code)) {
				ImageIcon icon = new ImageIcon(codewj());
				codePanel.getGraphics().drawImage(icon.getImage(), 0, 0, null);
				return "请填写验证码";
			} else {
				if (!validate(code)) {
					return "校验验证码失败";
				}
			}
			stopFlag = false;
			worker = new SwingWorker<String, String>() {
				@Override
				protected String doInBackground() throws Exception {
					String rtv = "";
					OutputStreamWriter fw = null;
					try {
						String fileName = savePath + "\\" + (new Date()).getTime() + ".csv";
						fw = new OutputStreamWriter(new FileOutputStream(fileName), "GBK");
						fw.write("年份,年份ID,文理,文理ID,本专,本专ID,分数,URL");
						// 如果前面所有字段都填充完整，那么开始抓取
						for (String nf_key : nf.keySet()) {
							String nf_value = nf.get(nf_key);
							for (String wl_key : wl.keySet()) {
								String wl_value = wl.get(wl_key);
								for (String bz_key : bz.keySet()) {
									String bz_value = bz.get(bz_key);
									for (int score = lowScore; score <= highScore; score++) {
										try {
											String url = fs(score, nf_key, wl_key, bz_key);
											String line = nf_value + "," + nf_key + "," + wl_value + "," + wl_key + "," + bz_value + "," + bz_key + "," + score + "," + url;
											fw.write("\r\n" + line);
											this.publish(line);
										} catch (Exception e) {
											e.printStackTrace();
										}
										if(stopFlag)
											break;
									}
									if(stopFlag)
										break;
								}
								if(stopFlag)
									break;
							}
							if(stopFlag)
								break;
						}
						fw.close();
						if(stopFlag){
							rtv = "用户中止进程，文件已生成：" + fileName;
						}else{
							rtv = "执行完成，文件已生成：" + fileName;
						}
					} catch (Exception e) {
					} finally {
						if (fw != null)
							try {
								fw.close();
							} catch (IOException e) {
							}
					}
					return rtv;
				}

				@Override
				protected void process(List<String> chunks) {
					for (String message : chunks) {
						logger_info(message);
					}
					statusLabel.setText("数据抓取中...");
					beginButton.setEnabled(false);
					refreshButton.setEnabled(false);
				}

				@Override
				protected void done() {
					beginButton.setEnabled(true);
					refreshButton.setEnabled(true);
					try {
						statusLabel.setText(get());
					} catch (Exception e) {
					}
				}
			};
			worker.execute();
		} catch (Exception e) {
			rtv = "发生错误：" + e.getMessage();
		}
		return rtv;
	}

	/**
	 * 获取验证码
	 */
	private byte[] codewj() {
		// HttpClient
		CloseableHttpClient httpClient = httpClientBuilder.build();
		String url = "http://14wj.gk66.cn/ashx/codewj.ashx";
		HttpGet httpGet = new HttpGet(url);
		try {
			httpGet.setHeader("cookie", cookie);
			System.out.println("executing request " + httpGet.getURI());
			CloseableHttpResponse response = httpClient.execute(httpGet);
			ByteArrayOutputStream fos = null;
			try {
				HttpEntity entity = response.getEntity();
				InputStream is = entity.getContent();
				fos = new ByteArrayOutputStream();
				byte buf[] = new byte[4 * 1024];
				while ((is.read(buf)) != -1) {
					fos.write(buf);
				}
				fos.flush();
				return fos.toByteArray();
			} finally {
				response.close();
				fos.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				httpClient.close();
			} catch (IOException e) {
			}
		}
		return null;
	}

	private String fs(int fs, String nf, String wl, String bz) {
		String rtVal = null;
		// HttpClient
		CloseableHttpClient httpClient = httpClientBuilder.build();
		String url = "http://14wj.gk66.cn/wj/fs.aspx";
		HttpPost httpPost = new HttpPost(url);
		// 创建参数队列
		List<NameValuePair> formParams = new ArrayList<NameValuePair>();
		formParams.add(new BasicNameValuePair("__VIEWSTATE", __VIEWSTATE));
		formParams.add(new BasicNameValuePair("__EVENTVALIDATION", __EVENTVALIDATION));
		formParams.add(new BasicNameValuePair("fs", String.valueOf(fs)));
		formParams.add(new BasicNameValuePair("nf", nf));
		formParams.add(new BasicNameValuePair("wl", wl));
		formParams.add(new BasicNameValuePair("bz", bz));
		formParams.add(new BasicNameValuePair("rand", code));
		formParams.add(new BasicNameValuePair("ImageButton1.x", "69"));
		formParams.add(new BasicNameValuePair("ImageButton1.y", "8"));
		UrlEncodedFormEntity uefEntity;
		try {
			uefEntity = new UrlEncodedFormEntity(formParams, "UTF-8");
			httpPost.setEntity(uefEntity);
			httpPost.setHeader("cookie", cookie);
			// logger.info("executing request " + httpPost.getURI());
			CloseableHttpResponse response = httpClient.execute(httpPost);
			try {
				if (response.containsHeader("Location")) {
					rtVal = response.getFirstHeader("Location").getValue();
				}
			} finally {
				response.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭连接,释放资源
			try {
				httpClient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return rtVal;
	}

	private boolean validate(String code) {
		boolean rtVal = false;
		// HttpClient
		CloseableHttpClient httpClient = httpClientBuilder.build();
		String url = "http://14wj.gk66.cn/ashx/validate.ashx";
		HttpPost httpPost = new HttpPost(url);
		// 创建参数队列
		List<NameValuePair> formParams = new ArrayList<NameValuePair>();
		formParams.add(new BasicNameValuePair("code", code));
		UrlEncodedFormEntity uefEntity;
		try {
			uefEntity = new UrlEncodedFormEntity(formParams, "UTF-8");
			httpPost.setEntity(uefEntity);
			httpPost.setHeader("cookie", cookie);
			logger_info("executing request " + httpPost.getURI());
			CloseableHttpResponse response = httpClient.execute(httpPost);
			try {
				HttpEntity entity = response.getEntity();
				String rt = EntityUtils.toString(entity, "gb2312");
				if ("1".equals(rt)) {
					rtVal = true;
				}
			} finally {
				response.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭连接,释放资源
			try {
				httpClient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return rtVal;
	}
	
	private LinkedList<String> logList = new LinkedList<String>();
	private JLabel label;
	private JLabel label_6;
	private JButton refreshButton;
	private void logger_info(String logger) {
		if(logList.size()>18){
			logList.removeLast();
		}
		logList.addFirst(logger);
		resultTextArea.setText("");
		for(String str:logList){
			resultTextArea.append(str+"\r\n");
		}
	}
}
